package com.qujia.station.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author sanse
 * @version 1.0
 * @date 2021/12/21 19:57
 * @description: 验签工具
 */
@Component
@Slf4j
public class VerifySignUtil {

    /**
     * 获取签名
     *
     * @param json
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public static String getSign(JSONObject json, String key) {
        JSONObject jsonClone = (JSONObject) json.clone();
        jsonClone.remove("sign");
        if (!ObjectUtils.isEmpty(jsonClone.get("reqData"))) {
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(json.get("reqData")));
            jsonClone.put("reqData", jsonObject);
        }

        String context = getJsonOrderString(jsonClone);
        log.info("验签字符串【{}】", context);

        return createSign(context, key);
    }

    /**
     * MD5加密获取签名
     *
     * @param obj
     * @param key
     * @return
     */
    public String getMD5Sign(Object obj, String key) {
        Map<String, Object> map = JSONObject.parseObject(JSON.toJSONString(obj), Map.class);
        String signStr = map.entrySet().stream()
                .filter(e -> !e.getKey().equals("sign"))
                .map(e -> e.getKey() + "=" + e.getValue())
                .sorted().reduce((a, b) -> a + "&" + b).orElse("") + "&" + key;
        return DigestUtils.md5Hex(signStr.getBytes(StandardCharsets.UTF_8));
    }

//--------------------------------------------辅助函数--------------------------------------------//

    public static String createSign(String message, String signKey) {
        try {
            // 创建加密对象
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256".intern());
            // 传入要加密的字符串,按指定的字符集将字符串转换为字节流
            messageDigest.update((message + "&key=" + signKey).getBytes("UTF-8".intern()));
            byte byteBuffer[] = messageDigest.digest();
            // 將 byte转换为16进制string
            StringBuffer strHexString = new StringBuffer();
            for (int i = 0; i < byteBuffer.length; i++) {
                String hex = Integer.toHexString(0xff & byteBuffer[i]);
                if (hex.length() == 1) {
                    strHexString.append('0');
                }
                strHexString.append(hex);
            }
            return strHexString.toString();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            log.error("生成签名错误，【[}】", e.toString());
        }
        return null;
    }

    private static String getJsonOrderString(JSONObject json) {
        List<String> list = new ArrayList<>();
        json.forEach((k, v) -> {
            if (v instanceof String) {
                list.add(k + '=' + v);
            } else if (v instanceof BigDecimal) {
                list.add(k + '=' + v);
            } else if (v instanceof Integer) {
                list.add(k + '=' + v);
            } else if (v instanceof Long) {
                list.add(k + '=' + v);
            } else if (v instanceof JSONObject) {
                JSONObject jsonV = (JSONObject) v;
                list.add(k + '=' + getJsonOrderString(jsonV));
            }
        });
        list.sort(String::compareTo);
        return StringUtils.join(list, '&');
    }


    /**
     * @Description: 获取约定签名
     * @Param:
     * @return:
     */
    public String getAgreedSign(JSONObject json, String key){
        JSONObject jsonClone=(JSONObject) json.clone();
        String signType="SHA256";
        if (StringUtils.isBlank(signType)||StringUtils.isBlank(key)){
            log.error("未知签名类型或者key");

        }
        jsonClone.remove("sign");

        String context=getJsonOrderString(jsonClone);
        log.info("验签字符串【{}】", context);

        SignCreatorEnums signCreatorEnums=SignCreatorEnums.getEnum(signType);
        if (signCreatorEnums==null){
            log.error("签名生成器不存在，类型【{}】", signType);

        }
        return createSign(context, key);
    }
}
